{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4bdea44e",
   "metadata": {},
   "source": [
    "### 实践：宿舍人脸检测\n",
    "* 尝试存放宿舍4位同学的人脸信息到 人脸数据集（XXX栋XXX宿舍）:\n",
    "> 1. 完善faceset信息\n",
    "> 2. 实现人脸搜索和人脸对比，打印结果：是本人 OR 不是本人"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bfe5148",
   "metadata": {},
   "source": [
    "* 1. 创建FaceSet\n",
    "* 2. 查询FaceSet\n",
    "* 3. 存入face_token数据\n",
    "* 4. 获取FaceSet信息数据\n",
    "* 5. 人脸搜索\n",
    "* 6. 人脸对比\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "13424114",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 准备可能需要用到的各个模块\n",
    "import requests\n",
    "import search\n",
    "import detect\n",
    "import analyze\n",
    "import compare"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "9f1a52ec",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 存入api_key & api_secret\n",
    "API_KEY = \"5G6CNIUGghmy_JcyAxNV-bDSVWy0XeI4\"\n",
    "API_Secret = 'rdArZ6BfSA19vSCeC_ArYzk2jqXK00Mi'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "08223663",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建宿舍人脸数据库\n",
    "create_url = 'https://api-cn.faceplusplus.com/facepp/v3/faceset/create'\n",
    "payload = {\n",
    "    \"api_key\" : API_KEY,\n",
    "    \"api_secret\" : API_Secret,\n",
    "    }\n",
    "\n",
    "r1 = requests.post(url = create_url,params = payload)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "8009670c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Response [200]>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 检查运行状态\n",
    "r1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "5609e97f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'ff79ca1aa5e64f80309829a9b1b80356'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 这个是人脸数据库的特征码 即 查询faceset\n",
    "faceset_token = r1.json()['faceset_token']\n",
    "faceset_token"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "34ed7bea",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "51981b5de26cb75911b461b4369a8ead \n",
      " b9f8bb2a1b0e78c2dece56894001fe67 \n",
      " 7f5eb6d42cf44ed237c468650b12f7f6\n"
     ]
    }
   ],
   "source": [
    "# 获取宿舍人脸数据\n",
    "face1 = detect.face_detect(API_KEY,API_Secret,'kanekikeh.jpg')\n",
    "face1_token = face1['faces'][0]['face_token']\n",
    "\n",
    "face2 = detect.face_detect(API_KEY,API_Secret,'widow.png')\n",
    "face2_token = face2['faces'][0]['face_token']\n",
    "\n",
    "face3 = detect.face_detect(API_KEY,API_Secret,'spider2.jpg')\n",
    "face3_token = face3['faces'][0]['face_token']\n",
    "\n",
    "print(face1_token,'\\n',face2_token,'\\n',face3_token)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "9f196b1b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['51981b5de26cb75911b461b4369a8ead',\n",
       " 'b9f8bb2a1b0e78c2dece56894001fe67',\n",
       " '7f5eb6d42cf44ed237c468650b12f7f6']"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 用变量重命名人脸数据集\n",
    "face_tokens_all = [face1_token,face2_token,face3_token]\n",
    "face_tokens_all"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1f01838c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 添加宿舍人脸数据到数据库中\n",
    "add_url = \" https://api-cn.faceplusplus.com/facepp/v3/faceset/addface\"\n",
    "payload = {\n",
    "    \"api_key\" : API_KEY,\n",
    "    \"api_secret\" : API_Secret,\n",
    "    \"faceset_token\" : faceset_token,\n",
    "    \"face_tokens\" : face_tokens_all\n",
    "    }\n",
    "\n",
    "r2 = requests.post(url = create_url,params = payload)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2fa88abc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'faceset_token': '1a97e2059c6dfb84e071f33142e5c053',\n",
       " 'time_used': 500,\n",
       " 'face_count': 1,\n",
       " 'face_added': 1,\n",
       " 'request_id': '1649261659,d1ad889b-e71c-41fe-98c9-d695fe14951c',\n",
       " 'outer_id': '',\n",
       " 'failure_detail': []}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r2.json()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "59ee90b2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取faceset信息\n",
    "getdetail_url = 'https://api-cn.faceplusplus.com/facepp/v3/faceset/getdetail'\n",
    "payload = {\n",
    "    \"api_key\" : API_KEY,\n",
    "    \"api_secret\" : API_Secret,\n",
    "    \"faceset_token\" : '1a97e2059c6dfb84e071f33142e5c053'\n",
    "    }\n",
    "\n",
    "r3 = requests.post(url = getdetail_url,params = payload)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "af671164",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'faceset_token': '1a97e2059c6dfb84e071f33142e5c053',\n",
       " 'tags': '',\n",
       " 'time_used': 70,\n",
       " 'user_data': '',\n",
       " 'display_name': '',\n",
       " 'face_tokens': ['51981b5de26cb75911b461b4369a8ead'],\n",
       " 'face_count': 1,\n",
       " 'request_id': '1649261689,54809b47-a2aa-4ef3-a643-e6d3483bcc07',\n",
       " 'outer_id': ''}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r3\n",
    "r3.json()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "23fd8477",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>字段</th>\n",
       "      <th>类型</th>\n",
       "      <th>说明</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>request_id</td>\n",
       "      <td>String</td>\n",
       "      <td>用于区分每一次请求的唯一的字符串。</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>results</td>\n",
       "      <td>Array</td>\n",
       "      <td>搜索结果对象数组注：如果传入图片但图片中未检测到人脸，则无法进行人脸搜索，本字段不返回。</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>thresholds</td>\n",
       "      <td>Object</td>\n",
       "      <td>一组用于参考的置信度阈值，包含以下三个字段。每个字段的值为一个 [0,100] 的浮点数，小...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>image_id</td>\n",
       "      <td>String</td>\n",
       "      <td>传入的图片在系统中的标识。注：如果未传入图片，本字段不返回。</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>faces</td>\n",
       "      <td>Array</td>\n",
       "      <td>传入的图片中检测出的人脸数组，采用数组中的第一个人脸进行人脸搜索。注：如果未传入图片，本字段...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>time_used</td>\n",
       "      <td>Int</td>\n",
       "      <td>整个请求所花费的时间，单位为毫秒。</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>error_message</td>\n",
       "      <td>String</td>\n",
       "      <td>当请求失败时才会返回此字符串，具体返回内容见后续错误信息章节。否则此字段不存在。</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              字段      类型                                                 说明\n",
       "0     request_id  String                                  用于区分每一次请求的唯一的字符串。\n",
       "1        results   Array       搜索结果对象数组注：如果传入图片但图片中未检测到人脸，则无法进行人脸搜索，本字段不返回。\n",
       "2     thresholds  Object  一组用于参考的置信度阈值，包含以下三个字段。每个字段的值为一个 [0,100] 的浮点数，小...\n",
       "3       image_id  String                     传入的图片在系统中的标识。注：如果未传入图片，本字段不返回。\n",
       "4          faces   Array  传入的图片中检测出的人脸数组，采用数组中的第一个人脸进行人脸搜索。注：如果未传入图片，本字段...\n",
       "5      time_used     Int                                  整个请求所花费的时间，单位为毫秒。\n",
       "6  error_message  String           当请求失败时才会返回此字符串，具体返回内容见后续错误信息章节。否则此字段不存在。"
      ]
     },
     "execution_count": 76,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 由 search 的图标可知，利用 条件判断 thresholds 可知是否是同一个的概率\n",
    "# 补充图表说明：\n",
    "# 一组用于参考的置信度阈值，包含以下三个字段。每个字段的值为一个 [0,100] 的浮点数，小数点后 3 位有效数字。\n",
    "# 1e-3：误识率为千分之一的置信度阈值；\n",
    "# 1e-4：误识率为万分之一的置信度阈值；\n",
    "# 1e-5：误识率为十万分之一的置信度阈值；\n",
    "# 如果置信值低于“千分之一”阈值则不建议认为是同一个人；如果置信值超过“十万分之一”阈值，则是同一个人的几率非常高。\n",
    "# 请注意：阈值不是静态的，每次返回的阈值不保证相同，所以没有持久化保存阈值的必要，更不要将当前调用返回的 confidence 与之前调用返回的阈值比较。\n",
    "# 注：如果传入图片但图片中未检测到人脸，则无法进行人脸搜索，本字段不返回。\n",
    "\n",
    "import pandas as pd\n",
    "pd.read_html(\"\"\"<table class=\"wrapped confluenceTable\"><colgroup><col><col><col></colgroup><tbody><tr><th class=\"confluenceTh\"><p><span style=\"color: rgb(0,0,0);\">字段</span></p></th><th class=\"confluenceTh\"><p><span style=\"color: rgb(0,0,0);\">类型</span></p></th><th class=\"confluenceTh\"><p><span style=\"color: rgb(0,0,0);\">说明</span></p></th></tr><tr><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">request_id</span></p></td><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">String</span></p></td><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">用于区分每一次请求的唯一的字符串。</span></p></td></tr><tr><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">results</span></p></td><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">Array</span></p></td><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">搜索结果对象数组</span></p><p><span style=\"color: rgb(0,0,0);\">注：如果传入图片但图片中未检测到人脸，则无法进行人脸搜索，本字段不返回。</span></p></td></tr><tr><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">thresholds</span></p></td><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">Object</span></p></td><td class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">一组用于参考的置信度阈值，包含以下三个字段。每个字段的值为一个 [0,100] 的浮点数，小数点后 3 位有效数字。</span></p><ul><li><span style=\"color: rgb(0,0,0);\">1e-3：误识率为千分之一的置信度阈值；</span></li><li><span style=\"color: rgb(0,0,0);\">1e-4：误识率为万分之一的置信度阈值；</span></li><li><span style=\"color: rgb(0,0,0);\">1e-5：误识率为十万分之一的置信度阈值；</span></li></ul><p><span style=\"color: rgb(0,0,0);\">如果置信值低于“千分之一”阈值则不建议认为是同一个人；如果置信值超过“十万分之一”阈值，则是同一个人的几率非常高。</span></p><p><span style=\"color: rgb(0,0,0);\">请注意：阈值不是静态的，每次返回的阈值不保证相同，所以没有持久化保存阈值的必要，更不要将当前调用返回的 confidence 与之前调用返回的阈值比较。</span></p><p style=\"text-align: justify;\"><span style=\"color: rgb(0,0,0);\">注：如果传入图片但图片中未检测到人脸，则无法进行人脸搜索，本字段不返回。</span></p></td></tr><tr><td colspan=\"1\" class=\"confluenceTd\"><span style=\"color: rgb(0,0,0);\">image_id</span></td><td colspan=\"1\" class=\"confluenceTd\"><span style=\"color: rgb(0,0,0);\">String</span></td><td colspan=\"1\" class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">传入的图片在系统中的标识。</span></p><p><span style=\"color: rgb(0,0,0);\">注：如果未传入图片，本字段不返回。</span></p></td></tr><tr><td colspan=\"1\" class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">faces</span></p></td><td colspan=\"1\" class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">Array</span></p></td><td colspan=\"1\" class=\"confluenceTd\"><p><span style=\"color: rgb(0,0,0);\">传入的图片中检测出的人脸数组，采用数组中的第一个人脸进行人脸搜索。</span></p><p><span style=\"color: rgb(0,0,0);\">注：如果未传入图片，本字段不返回。如果没有检测出人脸则为空数组</span></p></td></tr><tr><td colspan=\"1\" class=\"confluenceTd\"><p style=\"text-align: justify;\"><span style=\"color: rgb(0,0,0);\">time_used</span></p></td><td colspan=\"1\" class=\"confluenceTd\"><p style=\"text-align: justify;\"><span style=\"color: rgb(0,0,0);\">Int</span></p></td><td colspan=\"1\" class=\"confluenceTd\"><p style=\"text-align: justify;\"><span style=\"color: rgb(0,0,0);\">整个请求所花费的时间，单位为毫秒。</span></p></td></tr><tr><td colspan=\"1\" class=\"confluenceTd\"><p style=\"text-align: justify;\"><span style=\"color: rgb(0,0,0);\">error_message</span></p></td><td colspan=\"1\" class=\"confluenceTd\"><p style=\"text-align: justify;\"><span style=\"color: rgb(0,0,0);\">String</span></p></td><td colspan=\"1\" class=\"confluenceTd\"><p style=\"text-align: justify;\"><span style=\"color: rgb(0,0,0);\">当请求失败时才会返回此字符串，具体返回内容见后续错误信息章节。否则此字段不存在。</span></p></td></tr></tbody></table>\"\"\")[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "369ef112",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "欢迎回到宿舍！\n"
     ]
    }
   ],
   "source": [
    "# 开始进行数据库中的人脸搜索\n",
    "result = search.face_search(API_KEY,API_Secret,'spider2.jpg','1a97e2059c6dfb84e071f33142e5c053')\n",
    "result\n",
    "\n",
    "# 获取比对结果置信度\n",
    "result_confidence = result['results'][0]['confidence']\n",
    "result_confidence\n",
    "\n",
    "# 获取误识率为十万分之一的置信度阈值\n",
    "result_thresholds = result['thresholds']['1e-3']\n",
    "result_thresholds\n",
    "# 如果置信值超过“十万分之一”阈值，则是同一个人的几率非常高\n",
    "if result_confidence < result_thresholds:\n",
    "    print('欢迎回到宿舍！')\n",
    "else:\n",
    "    print('同学，你走错宿舍啦！')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "ff672ae8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "同学，你走错宿舍啦！\n"
     ]
    }
   ],
   "source": [
    "# 再次进行数据库中的人脸搜索(这是不在数据库里面的)\n",
    "search.face_search(API_KEY,API_Secret,'Liu.jpeg','1a97e2059c6dfb84e071f33142e5c053')\n",
    "# 获取比对结果置信度\n",
    "result_confidence = result['results'][0]['confidence']\n",
    "result_confidence\n",
    "\n",
    "# 获取误识率为十万分之一的置信度阈值\n",
    "result_thresholds = result['thresholds']['1e-3']\n",
    "result_thresholds\n",
    "# 如果置信值超过“十万分之一”阈值，则是同一个人的几率非常高\n",
    "if result_confidence > result_thresholds:\n",
    "    print('欢迎回到宿舍！')\n",
    "else:\n",
    "    print('同学，你走错宿舍啦！')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
